#pragma once

#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>

#include "handle.h"

namespace WCMM{

class CFile : public CHandle
{
public:
	CFile() throw(){}

	CFile(IN CFile& file) throw() : CHandle(file){}

	explicit CFile(_In_ HANDLE hFile) throw() : CHandle( hFile ){}


	BOOL Create(
		_In_z_ LPCTSTR szFilename,
		_In_ DWORD dwDesiredAccess,
		_In_ DWORD dwShareMode,
		_In_ DWORD dwCreationDisposition,
		_In_opt_ DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL,
		_In_opt_ LPSECURITY_ATTRIBUTES lpsa = NULL,
		_In_opt_ HANDLE hTemplateFile = NULL
	) throw();

	BOOL GetSize(
		_Out_ ULONGLONG& nLen
	) const throw();

	BOOL SetSize(
		_In_ ULONGLONG nNewLen
	) throw();

	BOOL Seek( 
		_In_ LONGLONG nOffset, 
		_In_ DWORD dwFrom = FILE_CURRENT
	) throw();

	BOOL Read( 
		_Out_writes_bytes_(nBufSize) LPVOID pBuffer, 
		_In_ DWORD nBufSize
	) throw();

	BOOL Read( 
		_Out_writes_bytes_(nBufSize) LPVOID pBuffer, 
		_In_ DWORD nBufSize, 
		_Out_ DWORD& nBytesRead
	) throw();

	BOOL Read( 
		_Out_writes_bytes_(nBufSize) LPVOID pBuffer, 
		_In_ DWORD nBufSize, 
		_In_ LPOVERLAPPED pOverlapped
	) throw();

	BOOL Read( 
		_Out_writes_bytes_(nBufSize) LPVOID pBuffer, 
		_In_ DWORD nBufSize, 
		_Inout_ LPOVERLAPPED pOverlapped, 
		_In_ LPOVERLAPPED_COMPLETION_ROUTINE pfnCompletionRoutine
	) throw();

	BOOL Write( 
		_In_reads_bytes_(nBufSize) LPCVOID pBuffer, 
		_In_ DWORD nBufSize, 
		_Out_opt_ DWORD* pnBytesWritten = NULL
	) throw();

	BOOL Write( 
		_In_reads_bytes_(nBufSize) LPCVOID pBuffer, 
		_In_ DWORD nBufSize, 
		_Inout_opt_ LPOVERLAPPED pOverlapped
	) throw();

	BOOL Write( 
		_In_reads_bytes_(nBufSize) LPCVOID pBuffer, 
		_In_ DWORD nBufSize, 
		_Inout_ LPOVERLAPPED pOverlapped, 
		_In_opt_ LPOVERLAPPED_COMPLETION_ROUTINE pfnCompletionRoutine
	) throw();

	BOOL GetOverlappedResult( 
		_In_ LPOVERLAPPED pOverlapped, 
		_Out_ DWORD& dwBytesTransferred, 
		_In_ BOOL bWait
	) throw();

	BOOL GetPosition(
		_Out_ ULONGLONG& nPos
	) const throw();

	BOOL Flush() throw();

	BOOL LockRange( 
		_In_ ULONGLONG nPos, 
		_In_ ULONGLONG nCount
	) throw();

	BOOL UnlockRange( 
		_In_ ULONGLONG nPos, 
		_In_ ULONGLONG nCount
	) throw();
};


class CTemporaryFile : public CFile
{
public:
	CTemporaryFile() throw()
	{
	}

	~CTemporaryFile() throw()
	{
		//
		// Ensure that the temporary file is closed and deleted,
		// if necessary.
		//

		if (m_h != NULL){
			Close();
		}
	}
	BOOL Create( 
		_In_opt_z_ LPCTSTR pszDir = NULL, 
		_In_ DWORD dwDesiredAccess = GENERIC_WRITE
	) throw();

	void Close() throw();

	BOOL Close(
		_In_opt_z_ LPCTSTR szNewName
	) throw();

	BOOL HandsOff() throw();

	BOOL HandsOn() throw();

	LPCTSTR TempFileName() throw();

private:
	TCHAR m_szTempFileName[_MAX_FNAME+1];
	DWORD m_dwAccess;
};


class CFileMappingBase
{
public:
	CFileMappingBase() throw();
	CFileMappingBase(_In_ CFileMappingBase& OrgMap);
	~CFileMappingBase() throw();

	BOOL MapFile( 
		_In_ HANDLE hFile, 
		_In_ SIZE_T nMappingSize = 0, 
		_In_ ULONGLONG nOffset = 0, 
		_In_ DWORD dwMappingProtection = PAGE_READONLY, 
		_In_ DWORD dwViewDesiredAccess = FILE_MAP_READ
	) throw();

	BOOL MapSharedMem( 
		_In_ SIZE_T nMappingSize, 
		_In_z_ LPCTSTR szName, 
		_Out_opt_ BOOL* pbAlreadyExisted = NULL, 
		_In_opt_ LPSECURITY_ATTRIBUTES lpsa = NULL, 
		_In_ DWORD dwMappingProtection = PAGE_READWRITE, 
		_In_ DWORD dwViewDesiredAccess = FILE_MAP_ALL_ACCESS
	) throw();

	BOOL OpenMapping( 
		_In_z_ LPCTSTR szName, 
		_In_ SIZE_T nMappingSize, 
		_In_ ULONGLONG nOffset = 0, 
		_In_ DWORD dwViewDesiredAccess = FILE_MAP_ALL_ACCESS
	) throw();

	BOOL Unmap() throw();

	void* GetData() const throw();

	HANDLE GetHandle() const throw();

	SIZE_T GetMappingSize() throw();

	BOOL CopyFrom(
		_In_ CFileMappingBase& OrgMap
	) throw();

	CFileMappingBase& operator=(
		_In_ CFileMappingBase& OrgMap
	);

private:
	void* m_pData;
	SIZE_T m_nMappingSize;
	HANDLE m_hMapping;
	ULARGE_INTEGER m_nOffset;
	DWORD m_dwViewDesiredAccess;
};

template <typename T = char>
class CWMFileMapping : 
	public CFileMappingBase
{
public:
	operator T*() const throw()
	{
		return reinterpret_cast<T*>(GetData());
	}
};

}